package com.devbobcorn.misaka.blocks;

import java.util.Map;
import java.util.Random;

import javax.annotation.Nullable;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;

public class CandleMisakaCakeBlock extends Block {
    public static final BooleanProperty LIT = BlockStateProperties.LIT;
    protected static final VoxelShape CAKE_SHAPE = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D);
    protected static final VoxelShape DATE_SHAPE = Block.box(3.0D, 8.0D, 7.0D, 13.0D, 13.0D, 9.0D);
    protected static final VoxelShape MISAKA_SHAPE = VoxelShapes.or(CAKE_SHAPE, DATE_SHAPE);
    private static final Map<Item, CandleMisakaCakeBlock> BY_DYE = Maps.newHashMap();
    private static final Iterable<Vector3d> PARTICLE_OFFSETS = ImmutableList.of(
        new Vector3d(0.28125D, 0.9375D, 0.5D),
        new Vector3d(0.71875D, 0.9375D, 0.5D)
    );

    @Nullable
    public final Item DyeItem;

    public CandleMisakaCakeBlock(Properties settings) {
        super(settings);
        DyeItem = null;
    }

    public CandleMisakaCakeBlock(Item dyeItem, Properties settings) {
        super(settings);
        DyeItem = dyeItem;
        BY_DYE.put(dyeItem, this);
    }

    protected void createBlockStateDefinition(StateContainer.Builder<Block, BlockState> builder) {
        builder.add(LIT);
    }

    public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext ctx) {
        return MISAKA_SHAPE;
    }

    public void animateTick(BlockState state, World world, BlockPos pos, Random random) {
        if (state.getValue(LIT)) {
            PARTICLE_OFFSETS.forEach((offset) -> {
                addCandleParticles(world,
                        offset.add((double)pos.getX(), (double)pos.getY(), (double)pos.getZ()), random);
            });
        }
    }

    private static void addCandleParticles(World world, Vector3d pos, Random random) {
        float f = random.nextFloat();
        if (f < 0.3F)
            world.addParticle(ParticleTypes.SMOKE, pos.x, pos.y, pos.z, 0.0D, 0.0D, 0.0D);

        world.addParticle(ParticleTypes.FLAME, pos.x, pos.y, pos.z, 0.0D, 0.0D, 0.0D);
    }
    
    public static void extinguish(@Nullable PlayerEntity player, BlockState state, IWorld world, BlockPos pos) {
        setLit(world, state, pos, false);
        if (state.getBlock() instanceof CandleMisakaCakeBlock) {
            PARTICLE_OFFSETS.forEach((offset) -> {
                world.addParticle(ParticleTypes.SMOKE, (double)pos.getX() + offset.x(),
                        (double)pos.getY() + offset.y(), (double)pos.getZ() + offset.z(),
                        0.0D, 0.1D, 0.0D);
            });
        }

        world.playSound((PlayerEntity)null, pos, SoundEvents.EXPERIENCE_BOTTLE_THROW, SoundCategory.BLOCKS, 1.0F, 1.0F);
        // TODO Fix world.levelEvent(player, LevelEvent.BLOCK_CHANGE, pos);
    }

    private static void setLit(IWorld world, BlockState state, BlockPos pos, boolean lit) {
        world.setBlock(pos, state.setValue(LIT, Boolean.valueOf(lit)), 11);
    }

    @Override
    public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) {
        ItemStack itemstack = player.getItemInHand(hand);
        if (itemstack.getItem() != Items.FLINT_AND_STEEL && itemstack.getItem() != Items.FIRE_CHARGE) {
            if (candleHit(hit) && player.getItemInHand(hand).isEmpty() && state.getValue(LIT)) {
                extinguish(player, state, world, pos);
                return ActionResultType.sidedSuccess(world.isClientSide);
            } else {
                ActionResultType result = MisakaCakeBlock.eatSlice(world, pos, ModBlocks.MISAKA_CAKE.get().defaultBlockState(), player);
                if (result.consumesAction()) {
                    dropResources(state, world, pos);
                }

                return result;
            }
        } else {
            return ActionResultType.PASS;
        }
    }

    protected static boolean candleHit(BlockRayTraceResult hit) {
        return hit.getLocation().y - (double) hit.getBlockPos().getY() > 0.5D;
    }

}
